/**
 * 预约时间表组件
 *
 * 功能特性：
 * - 拖拽创建时间段
 * - 实时冲突检测
 * - 多球台时间表显示
 * - 预约块的编辑和移动
 * - 时间表的缩放和滚动
 */

class ReservationSchedule {
    constructor(container, options = {}) {
        this.container = typeof container === 'string' ? document.querySelector(container) : container;
        this.options = {
            // 默认配置
            startHour: 8,
            endHour: 22,
            slotDuration: 30, // 分钟
            minDuration: 60, // 最小预约时长（分钟）
            maxDuration: 240, // 最大预约时长（分钟）
            timeFormat: '24h', // 24h 或 12h
            showWeekend: true,
            allowDrag: true,
            allowResize: true,
            allowCreate: true,
            tables: [], // 球台列表
            coaches: [], // 教练列表
            reservations: [], // 预约列表
            conflictStrategy: 'warn', // warn, prevent, allow
            onEventCreate: null,
            onEventUpdate: null,
            onEventDelete: null,
            onEventClick: null,
            onSlotClick: null,
            onConflictDetected: null,
            ...options
        };

        this.currentDate = new Date();
        this.viewType = 'day'; // day, week
        this.dragState = {
            isDragging: false,
            isResizing: false,
            isCreating: false,
            element: null,
            originalEvent: null,
            startX: 0,
            startY: 0,
            startTime: null,
            endTime: null,
            tableId: null
        };

        this.selectedEvent = null;
        this.timeScale = 1; // 时间缩放比例

        this.init();
    }

    init() {
        this.render();
        this.bindEvents();
        this.loadData();
    }

    render() {
        const html = `
            <div class="reservation-schedule">
                <div class="schedule-toolbar">
                    <div class="toolbar-left">
                        <div class="view-selector">
                            <button type="button" class="btn btn-sm ${this.viewType === 'day' ? 'btn-primary' : 'btn-outline-primary'}"
                                    data-view="day">日视图</button>
                            <button type="button" class="btn btn-sm ${this.viewType === 'week' ? 'btn-primary' : 'btn-outline-primary'}"
                                    data-view="week">周视图</button>
                        </div>
                        <div class="date-navigator">
                            <button type="button" class="btn btn-sm btn-outline-secondary" data-action="prev">
                                <i class="fas fa-chevron-left"></i>
                            </button>
                            <span class="current-date">${this.formatDateRange()}</span>
                            <button type="button" class="btn btn-sm btn-outline-secondary" data-action="next">
                                <i class="fas fa-chevron-right"></i>
                            </button>
                            <button type="button" class="btn btn-sm btn-outline-primary" data-action="today">今天</button>
                        </div>
                    </div>
                    <div class="toolbar-right">
                        <div class="zoom-controls">
                            <button type="button" class="btn btn-sm btn-outline-secondary" data-action="zoom-out">
                                <i class="fas fa-search-minus"></i>
                            </button>
                            <span class="zoom-level">${Math.round(this.timeScale * 100)}%</span>
                            <button type="button" class="btn btn-sm btn-outline-secondary" data-action="zoom-in">
                                <i class="fas fa-search-plus"></i>
                            </button>
                        </div>
                        <button type="button" class="btn btn-sm btn-success" data-action="create-event">
                            <i class="fas fa-plus me-1"></i>新建预约
                        </button>
                        <button type="button" class="btn btn-sm btn-outline-secondary" data-action="refresh">
                            <i class="fas fa-sync-alt"></i>
                        </button>
                    </div>
                </div>

                <div class="schedule-container">
                    <div class="schedule-sidebar">
                        ${this.renderSidebar()}
                    </div>
                    <div class="schedule-main">
                        <div class="schedule-header">
                            ${this.renderHeader()}
                        </div>
                        <div class="schedule-body">
                            <div class="schedule-grid">
                                ${this.renderGrid()}
                            </div>
                            <div class="schedule-events">
                                ${this.renderEvents()}
                            </div>
                        </div>
                    </div>
                </div>

                <div class="schedule-minimap">
                    ${this.renderMinimap()}
                </div>
            </div>
        `;

        this.container.innerHTML = html;
        this.cacheElements();
    }

    cacheElements() {
        this.elements = {
            toolbar: this.container.querySelector('.schedule-toolbar'),
            currentDate: this.container.querySelector('.current-date'),
            zoomLevel: this.container.querySelector('.zoom-level'),
            sidebar: this.container.querySelector('.schedule-sidebar'),
            header: this.container.querySelector('.schedule-header'),
            body: this.container.querySelector('.schedule-body'),
            grid: this.container.querySelector('.schedule-grid'),
            events: this.container.querySelector('.schedule-events'),
            minimap: this.container.querySelector('.schedule-minimap')
        };
    }

    bindEvents() {
        // 工具栏事件
        this.elements.toolbar.addEventListener('click', (e) => {
            const action = e.target.getAttribute('data-action') || e.target.closest('[data-action]')?.getAttribute('data-action');
            const view = e.target.getAttribute('data-view');

            if (action) {
                this.handleToolbarAction(action);
            }

            if (view) {
                this.setView(view);
            }
        });

        // 网格事件
        this.elements.grid.addEventListener('mousedown', (e) => {
            if (e.target.classList.contains('time-slot')) {
                this.startCreating(e);
            }
        });

        this.elements.grid.addEventListener('mousemove', (e) => {
            if (this.dragState.isCreating) {
                this.updateCreating(e);
            }
        });

        this.elements.grid.addEventListener('mouseup', (e) => {
            if (this.dragState.isCreating) {
                this.endCreating(e);
            }
        });

        this.elements.grid.addEventListener('click', (e) => {
            if (e.target.classList.contains('time-slot')) {
                this.handleSlotClick(e);
            }
        });

        // 事件块事件
        this.elements.events.addEventListener('mousedown', (e) => {
            const eventElement = e.target.closest('.schedule-event');
            if (eventElement) {
                if (e.target.classList.contains('resize-handle')) {
                    this.startResizing(e, eventElement);
                } else {
                    this.startDragging(e, eventElement);
                }
            }
        });

        this.elements.events.addEventListener('click', (e) => {
            const eventElement = e.target.closest('.schedule-event');
            if (eventElement && !this.dragState.isDragging && !this.dragState.isResizing) {
                this.handleEventClick(eventElement);
            }
        });

        // 全局鼠标事件
        document.addEventListener('mousemove', (e) => {
            if (this.dragState.isDragging) {
                this.updateDragging(e);
            } else if (this.dragState.isResizing) {
                this.updateResizing(e);
            }
        });

        document.addEventListener('mouseup', (e) => {
            if (this.dragState.isDragging) {
                this.endDragging(e);
            } else if (this.dragState.isResizing) {
                this.endResizing(e);
            }
        });

        // 键盘事件
        document.addEventListener('keydown', (e) => {
            this.handleKeyboard(e);
        });

        // 滚轮事件（缩放）
        this.elements.body.addEventListener('wheel', (e) => {
            if (e.ctrlKey || e.metaKey) {
                e.preventDefault();
                const delta = e.deltaY > 0 ? -0.1 : 0.1;
                this.setZoom(this.timeScale + delta);
            }
        });

        // 窗口调整大小
        window.addEventListener('resize', () => {
            this.handleResize();
        });
    }

    renderSidebar() {
        let html = '<div class="sidebar-content">';

        // 时间轴
        html += '<div class="time-axis">';
        html += '<div class="time-header">时间</div>';

        for (let hour = this.options.startHour; hour <= this.options.endHour; hour++) {
            const height = 60 * this.timeScale; // 每小时的高度
            html += `
                <div class="time-label" style="height: ${height}px">
                    <span>${this.formatHour(hour)}</span>
                </div>
            `;
        }

        html += '</div>';

        // 球台列表
        if (this.viewType === 'day') {
            html += '<div class="tables-list">';
            html += '<div class="tables-header">球台</div>';

            this.options.tables.forEach(table => {
                html += `
                    <div class="table-item" data-table-id="${table.id}">
                        <div class="table-name">${table.name}</div>
                        <div class="table-status ${table.status || 'available'}">${this.getTableStatusText(table.status)}</div>
                    </div>
                `;
            });

            html += '</div>';
        }

        html += '</div>';
        return html;
    }

    renderHeader() {
        let html = '<div class="header-content">';

        if (this.viewType === 'day') {
            html += `
                <div class="day-header">
                    <div class="day-date">${this.formatDate(this.currentDate)}</div>
                    <div class="day-name">${this.getDayName(this.currentDate)}</div>
                </div>
            `;
        } else {
            // 周视图标题
            const startOfWeek = this.getStartOfWeek(this.currentDate);
            for (let i = 0; i < 7; i++) {
                const date = new Date(startOfWeek);
                date.setDate(date.getDate() + i);

                if (!this.options.showWeekend && (date.getDay() === 0 || date.getDay() === 6)) {
                    continue;
                }

                const isToday = this.isToday(date);
                html += `
                    <div class="day-column-header ${isToday ? 'today' : ''}" data-date="${this.formatDateForData(date)}">
                        <div class="day-name">${this.getDayName(date)}</div>
                        <div class="day-date">${date.getDate()}</div>
                    </div>
                `;
            }
        }

        html += '</div>';
        return html;
    }

    renderGrid() {
        let html = '';
        const hourHeight = 60 * this.timeScale;

        for (let hour = this.options.startHour; hour < this.options.endHour; hour++) {
            for (let minute = 0; minute < 60; minute += this.options.slotDuration) {
                const top = ((hour - this.options.startHour) * 60 + minute) * this.timeScale;

                if (this.viewType === 'day') {
                    // 日视图 - 球台列
                    this.options.tables.forEach((table, index) => {
                        const left = index * 200; // 每个球台200px宽
                        const datetime = new Date(this.currentDate);
                        datetime.setHours(hour, minute, 0, 0);

                        const isOccupied = this.isSlotOccupied(table.id, datetime);
                        const classes = ['time-slot'];
                        if (isOccupied) classes.push('occupied');
                        if (hour % 2 === 0) classes.push('even-hour');

                        html += `
                            <div class="${classes.join(' ')}"
                                 style="top: ${top}px; left: ${left}px; width: 200px; height: ${this.options.slotDuration * this.timeScale}px"
                                 data-table-id="${table.id}"
                                 data-datetime="${datetime.toISOString()}"
                                 data-time="${hour}:${minute.toString().padStart(2, '0')}">
                            </div>
                        `;
                    });
                } else {
                    // 周视图 - 日期列
                    const startOfWeek = this.getStartOfWeek(this.currentDate);
                    let dayIndex = 0;

                    for (let i = 0; i < 7; i++) {
                        const date = new Date(startOfWeek);
                        date.setDate(date.getDate() + i);

                        if (!this.options.showWeekend && (date.getDay() === 0 || date.getDay() === 6)) {
                            continue;
                        }

                        const left = dayIndex * 150; // 每天150px宽
                        const datetime = new Date(date);
                        datetime.setHours(hour, minute, 0, 0);

                        const isOccupied = this.hasReservationsAt(datetime);
                        const classes = ['time-slot'];
                        if (isOccupied) classes.push('occupied');
                        if (hour % 2 === 0) classes.push('even-hour');

                        html += `
                            <div class="${classes.join(' ')}"
                                 style="top: ${top}px; left: ${left}px; width: 150px; height: ${this.options.slotDuration * this.timeScale}px"
                                 data-date="${this.formatDateForData(date)}"
                                 data-datetime="${datetime.toISOString()}"
                                 data-time="${hour}:${minute.toString().padStart(2, '0')}">
                            </div>
                        `;

                        dayIndex++;
                    }
                }
            }
        }

        // 小时分隔线
        for (let hour = this.options.startHour; hour <= this.options.endHour; hour++) {
            const top = (hour - this.options.startHour) * 60 * this.timeScale;
            html += `<div class="hour-line" style="top: ${top}px"></div>`;
        }

        return html;
    }

    renderEvents() {
        let html = '';

        this.options.reservations.forEach(reservation => {
            if (!this.isReservationInCurrentView(reservation)) return;

            const eventHtml = this.renderEvent(reservation);
            html += eventHtml;
        });

        return html;
    }

    renderEvent(reservation) {
        const startTime = new Date(reservation.start_time);
        const endTime = new Date(reservation.end_time);
        const duration = (endTime - startTime) / (1000 * 60); // 分钟

        let position;
        if (this.viewType === 'day') {
            position = this.getEventPositionForDay(reservation);
        } else {
            position = this.getEventPositionForWeek(reservation);
        }

        if (!position) return '';

        const { top, left, width, height } = position;

        const statusColors = {
            'pending': '#ffc107',
            'confirmed': '#17a2b8',
            'completed': '#28a745',
            'cancelled': '#dc3545'
        };

        const backgroundColor = statusColors[reservation.status] || '#6c757d';

        return `
            <div class="schedule-event ${reservation.status}"
                 style="top: ${top}px; left: ${left}px; width: ${width}px; height: ${height}px; background-color: ${backgroundColor}"
                 data-reservation-id="${reservation.id}"
                 data-table-id="${reservation.table_id}"
                 data-start="${reservation.start_time}"
                 data-end="${reservation.end_time}">

                <div class="event-content">
                    <div class="event-title">${reservation.student_name || '未知学员'}</div>
                    <div class="event-time">${this.formatTime(startTime)} - ${this.formatTime(endTime)}</div>
                    <div class="event-coach">${reservation.coach_name || '未分配教练'}</div>
                </div>

                ${this.options.allowResize ? '<div class="resize-handle resize-handle-top"></div>' : ''}
                ${this.options.allowResize ? '<div class="resize-handle resize-handle-bottom"></div>' : ''}

                <div class="event-actions">
                    <button type="button" class="btn-event-action" data-action="edit" title="编辑">
                        <i class="fas fa-edit"></i>
                    </button>
                    <button type="button" class="btn-event-action" data-action="delete" title="删除">
                        <i class="fas fa-trash"></i>
                    </button>
                </div>
            </div>
        `;
    }

    renderMinimap() {
        const totalHours = this.options.endHour - this.options.startHour;
        const minimapHeight = 200;
        const hourHeight = minimapHeight / totalHours;

        let html = '<div class="minimap-content">';
        html += '<div class="minimap-title">时间概览</div>';

        // 时间轴
        html += '<div class="minimap-timeline">';
        for (let hour = this.options.startHour; hour <= this.options.endHour; hour++) {
            const top = (hour - this.options.startHour) * hourHeight;
            html += `<div class="minimap-hour" style="top: ${top}px">${hour}</div>`;
        }
        html += '</div>';

        // 预约密度
        html += '<div class="minimap-density">';
        for (let hour = this.options.startHour; hour < this.options.endHour; hour++) {
            const reservationCount = this.getReservationCountForHour(hour);
            const density = Math.min(reservationCount / this.options.tables.length, 1);
            const top = (hour - this.options.startHour) * hourHeight;

            html += `
                <div class="density-bar"
                     style="top: ${top}px; height: ${hourHeight}px; opacity: ${density}"></div>
            `;
        }
        html += '</div>';

        // 当前视图指示器
        const currentViewTop = 0; // 计算当前视图位置
        const currentViewHeight = minimapHeight; // 计算当前视图高度
        html += `
            <div class="current-view-indicator"
                 style="top: ${currentViewTop}px; height: ${currentViewHeight}px"></div>
        `;

        html += '</div>';
        return html;
    }

    // 拖拽创建事件
    startCreating(e) {
        if (!this.options.allowCreate) return;

        const slot = e.target;
        const tableId = parseInt(slot.getAttribute('data-table-id'));
        const datetime = new Date(slot.getAttribute('data-datetime'));

        this.dragState = {
            isCreating: true,
            startTime: datetime,
            endTime: new Date(datetime.getTime() + this.options.minDuration * 60 * 1000),
            tableId: tableId,
            startY: e.clientY,
            element: this.createTempEvent(slot)
        };

        this.elements.events.appendChild(this.dragState.element);
        e.preventDefault();
    }

    updateCreating(e) {
        if (!this.dragState.isCreating) return;

        const deltaY = e.clientY - this.dragState.startY;
        const deltaMinutes = Math.round(deltaY / this.timeScale);
        const newEndTime = new Date(this.dragState.startTime.getTime() + Math.max(this.options.minDuration, deltaMinutes) * 60 * 1000);

        this.dragState.endTime = newEndTime;
        this.updateTempEvent(this.dragState.element, this.dragState.startTime, newEndTime);
    }

    endCreating(e) {
        if (!this.dragState.isCreating) return;

        const duration = (this.dragState.endTime - this.dragState.startTime) / (1000 * 60);

        if (duration >= this.options.minDuration && duration <= this.options.maxDuration) {
            const eventData = {
                tableId: this.dragState.tableId,
                startTime: this.dragState.startTime,
                endTime: this.dragState.endTime,
                duration: duration
            };

            if (this.checkConflict(eventData)) {
                this.handleConflict(eventData);
            } else {
                this.createEvent(eventData);
            }
        }

        // 清理临时元素
        if (this.dragState.element) {
            this.elements.events.removeChild(this.dragState.element);
        }

        this.resetDragState();
    }

    // 拖拽移动事件
    startDragging(e, eventElement) {
        if (!this.options.allowDrag) return;

        const reservationId = parseInt(eventElement.getAttribute('data-reservation-id'));
        const reservation = this.getReservationById(reservationId);

        this.dragState = {
            isDragging: true,
            element: eventElement,
            originalEvent: reservation,
            startX: e.clientX,
            startY: e.clientY,
            originalLeft: eventElement.offsetLeft,
            originalTop: eventElement.offsetTop
        };

        eventElement.classList.add('dragging');
        e.preventDefault();
    }

    updateDragging(e) {
        if (!this.dragState.isDragging) return;

        const deltaX = e.clientX - this.dragState.startX;
        const deltaY = e.clientY - this.dragState.startY;

        const newLeft = this.dragState.originalLeft + deltaX;
        const newTop = this.dragState.originalTop + deltaY;

        this.dragState.element.style.left = `${newLeft}px`;
        this.dragState.element.style.top = `${newTop}px`;

        // 计算新的时间和球台
        const newTimeAndTable = this.calculateTimeAndTableFromPosition(newLeft, newTop);
        this.showDragPreview(newTimeAndTable);
    }

    endDragging(e) {
        if (!this.dragState.isDragging) return;

        const newLeft = this.dragState.element.offsetLeft;
        const newTop = this.dragState.element.offsetTop;
        const newTimeAndTable = this.calculateTimeAndTableFromPosition(newLeft, newTop);

        if (newTimeAndTable && this.isValidMove(this.dragState.originalEvent, newTimeAndTable)) {
            this.updateEvent(this.dragState.originalEvent.id, newTimeAndTable);
        } else {
            // 恢复原位置
            this.dragState.element.style.left = `${this.dragState.originalLeft}px`;
            this.dragState.element.style.top = `${this.dragState.originalTop}px`;
        }

        this.dragState.element.classList.remove('dragging');
        this.hideDragPreview();
        this.resetDragState();
    }

    // 调整大小事件
    startResizing(e, eventElement) {
        if (!this.options.allowResize) return;

        const handle = e.target;
        const isTopHandle = handle.classList.contains('resize-handle-top');

        this.dragState = {
            isResizing: true,
            element: eventElement,
            isTopHandle: isTopHandle,
            startY: e.clientY,
            originalHeight: eventElement.offsetHeight,
            originalTop: eventElement.offsetTop
        };

        eventElement.classList.add('resizing');
        e.preventDefault();
    }

    updateResizing(e) {
        if (!this.dragState.isResizing) return;

        const deltaY = e.clientY - this.dragState.startY;

        if (this.dragState.isTopHandle) {
            // 调整顶部
            const newTop = this.dragState.originalTop + deltaY;
            const newHeight = this.dragState.originalHeight - deltaY;

            if (newHeight >= this.options.minDuration * this.timeScale) {
                this.dragState.element.style.top = `${newTop}px`;
                this.dragState.element.style.height = `${newHeight}px`;
            }
        } else {
            // 调整底部
            const newHeight = this.dragState.originalHeight + deltaY;

            if (newHeight >= this.options.minDuration * this.timeScale) {
                this.dragState.element.style.height = `${newHeight}px`;
            }
        }
    }

    endResizing(e) {
        if (!this.dragState.isResizing) return;

        const newTop = this.dragState.element.offsetTop;
        const newHeight = this.dragState.element.offsetHeight;
        const newTimes = this.calculateTimesFromPosition(newTop, newHeight);

        if (newTimes && this.isValidResize(this.dragState.originalEvent, newTimes)) {
            this.updateEvent(this.dragState.originalEvent.id, newTimes);
        } else {
            // 恢复原大小
            this.dragState.element.style.top = `${this.dragState.originalTop}px`;
            this.dragState.element.style.height = `${this.dragState.originalHeight}px`;
        }

        this.dragState.element.classList.remove('resizing');
        this.resetDragState();
    }

    // 工具栏操作
    handleToolbarAction(action) {
        switch (action) {
            case 'prev':
                this.navigate(-1);
                break;
            case 'next':
                this.navigate(1);
                break;
            case 'today':
                this.goToToday();
                break;
            case 'zoom-in':
                this.setZoom(Math.min(this.timeScale + 0.2, 3));
                break;
            case 'zoom-out':
                this.setZoom(Math.max(this.timeScale - 0.2, 0.5));
                break;
            case 'create-event':
                this.showCreateEventDialog();
                break;
            case 'refresh':
                this.refresh();
                break;
        }
    }

    // 事件处理
    handleEventClick(eventElement) {
        const reservationId = parseInt(eventElement.getAttribute('data-reservation-id'));
        const reservation = this.getReservationById(reservationId);

        this.selectedEvent = reservation;
        this.highlightEvent(eventElement);

        if (this.options.onEventClick) {
            this.options.onEventClick(reservation, eventElement);
        }
    }

    handleSlotClick(e) {
        const slot = e.target;
        const tableId = parseInt(slot.getAttribute('data-table-id'));
        const datetime = new Date(slot.getAttribute('data-datetime'));

        if (this.options.onSlotClick) {
            this.options.onSlotClick({
                tableId,
                datetime,
                element: slot
            });
        }
    }

    handleKeyboard(e) {
        switch (e.key) {
            case 'Delete':
                if (this.selectedEvent) {
                    this.deleteEvent(this.selectedEvent.id);
                }
                break;
            case 'Escape':
                this.clearSelection();
                break;
            case 'ArrowLeft':
                this.navigate(-1);
                e.preventDefault();
                break;
            case 'ArrowRight':
                this.navigate(1);
                e.preventDefault();
                break;
        }
    }

    // 视图方法
    setView(viewType) {
        this.viewType = viewType;
        this.updateToolbarViewButtons();
        this.render();
    }

    navigate(direction) {
        if (this.viewType === 'day') {
            this.currentDate.setDate(this.currentDate.getDate() + direction);
        } else {
            this.currentDate.setDate(this.currentDate.getDate() + (direction * 7));
        }
        this.updateView();
    }

    goToToday() {
        this.currentDate = new Date();
        this.updateView();
    }

    setZoom(scale) {
        this.timeScale = Math.max(0.5, Math.min(3, scale));
        this.elements.zoomLevel.textContent = `${Math.round(this.timeScale * 100)}%`;
        this.updateView();
    }

    updateView() {
        this.elements.currentDate.textContent = this.formatDateRange();
        this.elements.grid.innerHTML = this.renderGrid();
        this.elements.events.innerHTML = this.renderEvents();
        this.elements.minimap.innerHTML = this.renderMinimap();
    }

    // 工具方法
    getEventPositionForDay(reservation) {
        const startTime = new Date(reservation.start_time);
        const endTime = new Date(reservation.end_time);

        // 检查是否在当前日期
        if (startTime.toDateString() !== this.currentDate.toDateString()) {
            return null;
        }

        const tableIndex = this.options.tables.findIndex(t => t.id === reservation.table_id);
        if (tableIndex === -1) return null;

        const startMinutes = (startTime.getHours() - this.options.startHour) * 60 + startTime.getMinutes();
        const duration = (endTime - startTime) / (1000 * 60);

        return {
            top: startMinutes * this.timeScale,
            left: tableIndex * 200,
            width: 190, // 留10px间距
            height: duration * this.timeScale
        };
    }

    getEventPositionForWeek(reservation) {
        const startTime = new Date(reservation.start_time);
        const endTime = new Date(reservation.end_time);

        const startOfWeek = this.getStartOfWeek(this.currentDate);
        const endOfWeek = new Date(startOfWeek);
        endOfWeek.setDate(endOfWeek.getDate() + 6);

        // 检查是否在当前周
        if (startTime < startOfWeek || startTime > endOfWeek) {
            return null;
        }

        const daysDiff = Math.floor((startTime - startOfWeek) / (1000 * 60 * 60 * 24));
        const startMinutes = (startTime.getHours() - this.options.startHour) * 60 + startTime.getMinutes();
        const duration = (endTime - startTime) / (1000 * 60);

        return {
            top: startMinutes * this.timeScale,
            left: daysDiff * 150,
            width: 140, // 留10px间距
            height: duration * this.timeScale
        };
    }

    createTempEvent(slot) {
        const element = document.createElement('div');
        element.className = 'schedule-event temp-event';
        return element;
    }

    updateTempEvent(element, startTime, endTime) {
        const duration = (endTime - startTime) / (1000 * 60);
        const height = duration * this.timeScale;
        element.style.height = `${height}px`;
    }

    checkConflict(eventData) {
        return this.options.reservations.some(reservation => {
            if (reservation.table_id !== eventData.tableId) return false;

            const resStart = new Date(reservation.start_time);
            const resEnd = new Date(reservation.end_time);

            return (eventData.startTime < resEnd && eventData.endTime > resStart);
        });
    }

    handleConflict(eventData) {
        if (this.options.conflictStrategy === 'prevent') {
            this.showMessage('该时间段已被预约，请选择其他时间', 'error');
            return;
        }

        if (this.options.conflictStrategy === 'warn') {
            if (confirm('该时间段已有其他预约，是否仍要创建？')) {
                this.createEvent(eventData);
            }
            return;
        }

        // allow 策略直接创建
        this.createEvent(eventData);
    }

    createEvent(eventData) {
        if (this.options.onEventCreate) {
            this.options.onEventCreate(eventData);
        }
    }

    updateEvent(eventId, updateData) {
        if (this.options.onEventUpdate) {
            this.options.onEventUpdate(eventId, updateData);
        }
    }

    deleteEvent(eventId) {
        if (this.options.onEventDelete) {
            this.options.onEventDelete(eventId);
        }
    }

    // 辅助方法
    formatDateRange() {
        if (this.viewType === 'day') {
            return this.formatDate(this.currentDate);
        } else {
            const startOfWeek = this.getStartOfWeek(this.currentDate);
            const endOfWeek = new Date(startOfWeek);
            endOfWeek.setDate(endOfWeek.getDate() + 6);
            return `${this.formatDate(startOfWeek)} - ${this.formatDate(endOfWeek)}`;
        }
    }

    formatDate(date) {
        return `${date.getFullYear()}年${(date.getMonth() + 1).toString().padStart(2, '0')}月${date.getDate().toString().padStart(2, '0')}日`;
    }

    formatDateForData(date) {
        return date.toISOString().split('T')[0];
    }

    formatTime(date) {
        const hours = date.getHours();
        const minutes = date.getMinutes();

        if (this.options.timeFormat === '12h') {
            const ampm = hours >= 12 ? 'PM' : 'AM';
            const displayHours = hours % 12 || 12;
            return `${displayHours}:${minutes.toString().padStart(2, '0')} ${ampm}`;
        } else {
            return `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}`;
        }
    }

    formatHour(hour) {
        if (this.options.timeFormat === '12h') {
            const ampm = hour >= 12 ? 'PM' : 'AM';
            const displayHour = hour % 12 || 12;
            return `${displayHour} ${ampm}`;
        } else {
            return `${hour.toString().padStart(2, '0')}:00`;
        }
    }

    getDayName(date) {
        const days = ['周日', '周一', '周二', '周三', '周四', '周五', '周六'];
        return days[date.getDay()];
    }

    getStartOfWeek(date) {
        const start = new Date(date);
        const day = start.getDay();
        const diff = start.getDate() - day + (day === 0 ? -6 : 1);
        start.setDate(diff);
        start.setHours(0, 0, 0, 0);
        return start;
    }

    isToday(date) {
        const today = new Date();
        return date.toDateString() === today.toDateString();
    }

    isReservationInCurrentView(reservation) {
        const startTime = new Date(reservation.start_time);

        if (this.viewType === 'day') {
            return startTime.toDateString() === this.currentDate.toDateString();
        } else {
            const startOfWeek = this.getStartOfWeek(this.currentDate);
            const endOfWeek = new Date(startOfWeek);
            endOfWeek.setDate(endOfWeek.getDate() + 7);
            return startTime >= startOfWeek && startTime < endOfWeek;
        }
    }

    getReservationById(id) {
        return this.options.reservations.find(r => r.id === id);
    }

    isSlotOccupied(tableId, datetime) {
        return this.options.reservations.some(reservation => {
            return reservation.table_id === tableId &&
                   datetime >= new Date(reservation.start_time) &&
                   datetime < new Date(reservation.end_time);
        });
    }

    hasReservationsAt(datetime) {
        return this.options.reservations.some(reservation => {
            const startTime = new Date(reservation.start_time);
            return startTime.toDateString() === datetime.toDateString() &&
                   startTime.getHours() === datetime.getHours() &&
                   Math.floor(startTime.getMinutes() / this.options.slotDuration) === Math.floor(datetime.getMinutes() / this.options.slotDuration);
        });
    }

    getReservationCountForHour(hour) {
        return this.options.reservations.filter(reservation => {
            const startTime = new Date(reservation.start_time);
            return startTime.getHours() === hour;
        }).length;
    }

    getTableStatusText(status) {
        const statusMap = {
            'available': '可用',
            'maintenance': '维护中',
            'occupied': '使用中',
            'disabled': '已禁用'
        };
        return statusMap[status] || '未知';
    }

    resetDragState() {
        this.dragState = {
            isDragging: false,
            isResizing: false,
            isCreating: false,
            element: null,
            originalEvent: null,
            startX: 0,
            startY: 0,
            startTime: null,
            endTime: null,
            tableId: null
        };
    }

    showMessage(message, type = 'info') {
        console.log(`[${type.toUpperCase()}] ${message}`);
        // 可以集成 toastr 或其他消息库
        if (window.showAlert) {
            window.showAlert(type, message);
        }
    }

    // 公共API
    setData(data) {
        if (data.tables) this.options.tables = data.tables;
        if (data.reservations) this.options.reservations = data.reservations;
        if (data.coaches) this.options.coaches = data.coaches;
        this.updateView();
    }

    getSelectedEvent() {
        return this.selectedEvent;
    }

    setDate(date) {
        this.currentDate = new Date(date);
        this.updateView();
    }

    refresh() {
        this.loadData();
    }

    loadData() {
        // 这里应该从服务器加载数据
        // 为了演示，保持现有数据
        this.updateView();
    }

    destroy() {
        this.container.innerHTML = '';
    }
}

// 导出为全局变量
window.ReservationSchedule = ReservationSchedule;